package top.zhangjianyong.tools.indicator.strategy.impl;

import org.springframework.stereotype.Component;
import top.zhangjianyong.tools.entity.ETFData;
import top.zhangjianyong.tools.indicator.context.IndicatorContext;
import top.zhangjianyong.tools.indicator.model.TechnicalIndicatorResult;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * ADX（平均趋向指数）指标计算器
 * 窗口14，衡量趋势强度（0-100）
 *
 * @author zhangjianyong
 * @date 2024/01/01
 */
@Component
public class ADXIndicator extends AbstractIndicator {

    private static final String INDICATOR_NAME = "ADX";
    private static final int PERIOD = 14;

    @Override
    public String getName() {
        return INDICATOR_NAME;
    }

    @Override
    public int getMinDataSize() {
        return PERIOD * 2; // ADX需要计算多个中间值，需要更多数据
    }

    @Override
    protected TechnicalIndicatorResult doCalculate(IndicatorContext context) {
        List<ETFData> dataList = context.getDataList();

        // 计算+DM和-DM序列
        List<BigDecimal> plusDM = new ArrayList<>();
        List<BigDecimal> minusDM = new ArrayList<>();
        List<BigDecimal> trueRanges = new ArrayList<>();

        for (int i = 1; i < dataList.size(); i++) {
            ETFData current = dataList.get(i);
            ETFData previous = dataList.get(i - 1);

            BigDecimal currentPrice = current.getValue();
            BigDecimal previousPrice = previous.getValue();

            // 计算价格变化
            BigDecimal priceChange = currentPrice.subtract(previousPrice);

            // +DM：如果价格上涨，+DM = 价格变化，否则为0
            BigDecimal plusDMValue = priceChange.compareTo(BigDecimal.ZERO) > 0 ? priceChange : BigDecimal.ZERO;
            plusDM.add(plusDMValue);

            // -DM：如果价格下跌，-DM = |价格变化|，否则为0
            BigDecimal minusDMValue = priceChange.compareTo(BigDecimal.ZERO) < 0 ? priceChange.abs() : BigDecimal.ZERO;
            minusDM.add(minusDMValue);

            // 真实波幅（简化：使用价格变化幅度）
            BigDecimal trueRange = priceChange.abs();
            trueRanges.add(trueRange);
        }

        if (plusDM.size() < PERIOD) {
            return TechnicalIndicatorResult.failure(getName(), "数据不足，无法计算ADX");
        }

        // 计算+DI和-DI
        BigDecimal plusDI = calculateDI(plusDM, trueRanges, PERIOD);
        BigDecimal minusDI = calculateDI(minusDM, trueRanges, PERIOD);

        // 计算DX
        BigDecimal dx = calculateDX(plusDI, minusDI);

        // 计算ADX（DX的PERIOD日平滑移动平均）
        BigDecimal adx = calculateADX(dataList, dx, plusDI, minusDI);

        TechnicalIndicatorResult result = TechnicalIndicatorResult.success(getName());
        result.addValue("adx", adx.setScale(2, RoundingMode.HALF_UP));
        result.addValue("adx_14", adx.setScale(2, RoundingMode.HALF_UP));
        result.addValue("plus_di", plusDI.setScale(2, RoundingMode.HALF_UP));
        result.addValue("minus_di", minusDI.setScale(2, RoundingMode.HALF_UP));

        return result;
    }

    /**
     * 计算DI（方向指标）
     */
    private BigDecimal calculateDI(List<BigDecimal> dmList, List<BigDecimal> trueRanges, int period) {
        // 计算DM和TR的PERIOD日平滑平均值
        BigDecimal sumDM = BigDecimal.ZERO;
        BigDecimal sumTR = BigDecimal.ZERO;

        int startIndex = Math.max(0, dmList.size() - period);
        for (int i = startIndex; i < dmList.size(); i++) {
            sumDM = sumDM.add(dmList.get(i));
            sumTR = sumTR.add(trueRanges.get(i));
        }

        if (sumTR.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }

        // DI = (DM的平滑平均值 / TR的平滑平均值) * 100
        return sumDM.divide(sumTR, 4, RoundingMode.HALF_UP)
            .multiply(new BigDecimal(100));
    }

    /**
     * 计算DX（趋向指数）
     */
    private BigDecimal calculateDX(BigDecimal plusDI, BigDecimal minusDI) {
        BigDecimal diSum = plusDI.add(minusDI);
        if (diSum.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }

        BigDecimal diDiff = plusDI.subtract(minusDI).abs();
        return diDiff.divide(diSum, 4, RoundingMode.HALF_UP)
            .multiply(new BigDecimal(100));
    }

    /**
     * 计算ADX（DX的平滑移动平均）
     */
    private BigDecimal calculateADX(List<ETFData> dataList, BigDecimal currentDX, BigDecimal plusDI, BigDecimal minusDI) {
        // 简化实现：使用当前DX值
        // 完整实现需要维护DX序列并计算平滑移动平均
        return currentDX;
    }
}

